package tum0r.webengine.models.utils

import com.github.hui.quick.plugin.qrcode.wrapper.QrCodeGenWrapper
import com.github.hui.quick.plugin.qrcode.wrapper.QrCodeOptions
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
import java.awt.Color
import java.awt.image.BufferedImage
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.InputStream

/**
 * 说明: 生成二维码，基于qrcode-plugin，可以使用成员变量 builder 自定义设置（Java中使用getBuilder()方法获取builder）
 *
 * 创建者: tum0r
 *
 * 时间: 2021/9/1 12:43
 *
 * @param[height] 二维码高度
 * @param[width] 二维码宽度
 * @param[padding] 二维码边框
 */
data class QRCode(var height: Int, var width: Int, var padding: Int) {
    /**
     * 默认二维码高度300，宽度300，边框1
     */
    constructor() : this(300, 300, 1)

    /**
     * 错误信息
     */
    var errorMessage: String = ""

    /**
     * 二维码纠错级别
     */
    var errorCorrectionLevel = ErrorCorrectionLevel.Q

    /**
     * 二维码输出图片信息
     */
    var pictureType = "png"

    /**
     * 二维码样式
     */
    var drawStyle = QrCodeOptions.DrawStyle.RECT

    // region 定位点

    /**
     * 定位点外框颜色
     */
    var detectOutColor: Color? = null

    /**
     * 定位点内部颜色
     */
    var detectInColor: Color? = null

    // endregion

    // region 二维码背景
    /**
     * 二维码背景色
     */
    var drawBackgroundColor: Color? = null

    /**
     * 二维码背景图片
     */
    var drawBackgroundImage: File? = null

    /**
     * 二维码背景图片
     */
    var drawBackgroundBufferedImage: BufferedImage? = null

    /**
     * 二维码背景图片
     */
    var drawBackgroundInputStream: InputStream? = null

    /**
     * 是否设置了二维码背景图片
     */
    fun isDrawBackgroundImage() = drawBackgroundImage != null || drawBackgroundBufferedImage != null || drawBackgroundInputStream != null

    // endregion

    // region 二维码前景
    /**
     * 二维码前景色
     */
    var drawForegroundColor: Color? = null

    /**
     * 二维码前景图片
     */
    var drawForegroundImage: File? = null

    /**
     * 二维码前景图片
     */
    var drawForegroundBufferedImage: BufferedImage? = null

    /**
     * 二维码前景图片
     */
    var drawForegroundInputStream: InputStream? = null

    /**
     * 是否设置了二维码前景图片
     */
    fun isDrawForegroundImage() = drawForegroundImage != null || drawForegroundBufferedImage != null || drawForegroundInputStream != null

    // endregion

    // region 二维码Logo
    /**
     * 二维码Logo图片
     */
    var logo: File? = null

    /**
     * 二维码Logo图片
     */
    var logoBufferedImage: BufferedImage? = null

    /**
     * 二维码Logo图片
     */
    var logoInputStream: InputStream? = null

    /**
     * 二维码Logo圆角
     */
    var logoRate = 10

    /**
     * 二维码Logo透明度
     */
    var logoOpacity = 1.0f

    /**
     * 二维码Logo背景颜色
     */
    var logoBackgroundColor: Color? = null

    /**
     * 二维码Logo边框
     */
    var logoBorder = false

    /**
     * 二维码Logo边框颜色
     */
    var logoBorderColor: Color? = null

    /**
     * 二维码Logo样式
     */
    var logoStyle = QrCodeOptions.LogoStyle.CIRCLE

    /**
     * 是否设置了二维码Logo
     */
    fun isLogo() = this.logo != null || this.logoBufferedImage != null || this.logoInputStream != null
    // endregion

    // region 二维码背景
    /**
     * 二维码背景图片
     */
    var background: File? = null

    /**
     * 二维码背景图片
     */
    var backgroundBufferedImage: BufferedImage? = null

    /**
     * 二维码背景图片
     */
    var backgroundInputStream: InputStream? = null

    /**
     * 二维码背景图片透明度
     */
    var backgroundOpacity = 0.6f

    /**
     * 二维码背景高度
     */
    var backgroundHeight = 0

    /**
     * 二维码背景宽度
     */
    var backgroundWidth = 0

    /**
     * 二维码背景图片起始X坐标
     */
    var backgroundStartX = 0

    /**
     * 二维码背景图片起始Y坐标
     */
    var backgroundStartY = 0

    /**
     * 二维码背景图片样式
     */
    var backgroundStyle = QrCodeOptions.BgImgStyle.PENETRATE

    /**
     * 二维码背景图片是否设置
     */
    fun isBackground() = background != null || backgroundBufferedImage != null || backgroundInputStream != null
    // endregion

    /**
     * 二维码创建对象
     */
    var builder: QrCodeGenWrapper.Builder = QrCodeGenWrapper.of("")

    init {
        reBuild()
    }

    /**
     * 刷新二维码创建对象配置
     */
    fun reBuild() {
        builder.setH(this.height).setW(this.width).setPadding(this.padding).setErrorCorrection(this.errorCorrectionLevel).setPicType(this.pictureType).setDrawStyle(this.drawStyle)
        if (this.detectOutColor != null || this.detectInColor != null) {
            builder.setDetectSpecial()
            if (this.detectOutColor != null) builder.setDetectOutColor(this.detectOutColor)
            if (this.detectInColor != null) builder.setDetectInColor(this.detectInColor)
        }
        if (this.drawBackgroundColor != null) builder.setDrawBgColor(this.drawBackgroundColor)
        if (this.drawForegroundColor != null) builder.setDrawPreColor(this.drawForegroundColor)
        if (isDrawBackgroundImage()) {
            if (this.drawBackgroundImage != null) builder.setDrawBgImg(this.drawBackgroundImage!!.absolutePath)
            else if (this.drawBackgroundBufferedImage != null) builder.setDrawBgImg(this.drawBackgroundBufferedImage)
            else builder.setDrawBgImg(this.drawBackgroundInputStream)
        }

        if (isDrawForegroundImage()) {
            if (this.drawForegroundImage != null) builder.setDrawBgImg(this.drawForegroundImage!!.absolutePath)
            else if (this.drawForegroundBufferedImage != null) builder.setDrawBgImg(this.drawForegroundBufferedImage)
            else builder.setDrawBgImg(this.drawForegroundInputStream)
        }
        // 二维码Logo设置
        if (isLogo()) {
            if (this.logo != null) builder.setLogo(this.logo!!.absolutePath)
            else if (this.logoBufferedImage != null) builder.setLogo(this.logoBufferedImage)
            else builder.setLogo(this.logoInputStream)
            builder.setLogoRate(this.logoRate).setLogoOpacity(this.logoOpacity).setLogoBorder(this.logoBorder).setLogoStyle(this.logoStyle)
            if (this.logoBackgroundColor != null) builder.setLogoBgColor(this.logoBackgroundColor)
            if (this.logoBorderColor != null) builder.setLogoBgColor(this.logoBorderColor)
        }
        // 二维码背景设置
        if (isBackground()) {
            if (this.background != null) builder.setBgImg(this.background!!.absolutePath)
            else if (this.backgroundBufferedImage != null) builder.setBgImg(this.backgroundBufferedImage)
            else builder.setBgImg(this.backgroundInputStream)
            builder.setBgOpacity(this.backgroundOpacity)
            builder.setBgH(this.backgroundHeight)
            builder.setBgW(this.backgroundWidth)
            builder.setBgStartX(this.backgroundStartX)
            builder.setBgStartY(this.backgroundStartY)
            builder.setBgStyle(this.backgroundStyle)
        }
    }

    /**
     * 当DrawStyle为图片模式时设置
     *
     * @param[row] 行
     * @param[column] 列
     * @param[imagePath] 图片路径
     */
    fun addImg(row: Int, column: Int, imagePath: String): QrCodeGenWrapper.Builder = builder.addImg(row, column, imagePath)

    /**
     * 当DrawStyle为图片模式时设置
     *
     * @param[row] 行
     * @param[column] 列
     * @param[imageFile] 图片文件
     */
    fun addImg(row: Int, column: Int, imageFile: File): QrCodeGenWrapper.Builder = builder.addImg(row, column, imageFile.absolutePath)

    /**
     * 当DrawStyle为图片模式时设置
     *
     * @param[row] 行
     * @param[column] 列
     * @param[image] 图片的BufferedImage对象
     */
    fun addImg(row: Int, column: Int, image: BufferedImage): QrCodeGenWrapper.Builder = builder.addImg(row, column, image)

    /**
     * 当DrawStyle为图片模式时设置
     *
     * @param[row] 行
     * @param[column] 列
     * @param[imageInputStream] 图片的InputStream对象
     */
    fun addImg(row: Int, column: Int, imageInputStream: InputStream): QrCodeGenWrapper.Builder = builder.addImg(row, column, imageInputStream)

    /**
     * 生成二维码
     *
     * @param[content] 二维码内容
     * @param[type] 类型，0 Byte输出流，1 字符串，2 BufferedImage
     *
     * @return 生成失败时返回null
     */
    private fun generate(content: String, type: Int): Any? {
        return try {
            builder.msg = content
            when (type) {
                0 -> builder.asStream()
                1 -> builder.asString()
                2 -> builder.asBufferedImage()
                else -> null
            }
        } catch (e: Exception) {
            if (e.message != null) errorMessage = e.message!!
            null
        }
    }

    /**
     * 生成二维码字符输出流
     *
     * @param[content] 二维码内容
     *
     * @return 生成失败时返回null
     */
    fun generateAsStream(content: String): ByteArrayOutputStream? = generate(content, 0) as ByteArrayOutputStream?

    /**
     * 生成二维码字符串
     *
     * @param[content] 二维码内容
     *
     * @return 生成失败时返回null
     */
    fun generateAsString(content: String): String? = generate(content, 1) as String?

    /**
     * 生成二维码BufferedImage对象
     *
     * @param[content] 二维码内容
     *
     * @return 生成失败时返回null
     */
    fun generateAsBufferedImage(content: String): BufferedImage? = generate(content, 2) as BufferedImage?

    /**
     * 生成二维码File对象
     *
     * @param[content] 二维码内容
     * @param[path] 二维码文件路径
     *
     * @return 生成失败时返回null
     */
    fun generateAsFile(content: String, path: String): File? {
        return try {
            val result = File(path)
            builder.msg = content
            builder.asFile(result.absolutePath)
            result
        } catch (e: Exception) {
            if (e.message != null) errorMessage = e.message!!
            null
        }
    }

    /**
     * 生成二维码File对象
     *
     * @param[content] 二维码内容
     * @param[file] 二维码文件
     *
     * @return 生成失败时返回null
     */
    fun generateAsFile(content: String, file: File): File? = generateAsFile(content, file.absolutePath)
}
